/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package clusterAnalysis;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import units.CellType;
import units.MonkeyType;
import utils.FileUtils;
import utils.Handle;
import utils.Matthews;
import utils.fishersExact.FishersExactTest;

/**
 *
 * @author jamie
 */
public class ClusterIntersections {

    private TreeMap<String, TreeMap<Integer, List<Integer>>> clusterMembership;
    private int probeSetSize;
    private File outputFolder = new File("/Users/jamie/monkeys/clust/clusterComparisons");
    private File outputForPValueCorrection = new File("/Users/jamie/Dropbox/monkeys/clust/clusterComparisons/pValues.txt");
    private File inputFromPValueCorrection = new File("/Users/jamie/Dropbox/monkeys/clust/clusterComparisons/pValues_correct.txt");
    private int id = 1;
    private BufferedWriter pValuesWriter = FileUtils.getBufferedWriter(outputForPValueCorrection);

    public ClusterIntersections() {
        

        
    }

    public void calculateIntersections(){
        probeSetSize = getProbeSetSize();
        fillClusterMembership();
        List<ClusterComparison> comp_AL_AP = makeClusterComparisons("AL", "AP");
        List<ClusterComparison> comp_ML_MP = makeClusterComparisons("ML", "MP");
        List<ClusterComparison> comp_AL_ML = makeClusterComparisons("AL", "ML");
        List<ClusterComparison> comp_AP_MP = makeClusterComparisons("AP", "MP");
        try {
            output("AL", "AP", comp_AL_AP);
            output("ML", "MP", comp_ML_MP);
            output("AL", "ML", comp_AL_ML);
            output("AP", "MP", comp_AP_MP);

            pValuesWriter.close();
        } catch (IOException ex) {
            Logger.getLogger(ClusterIntersections.class.getName()).log(Level.SEVERE, null, ex);
        }
        addToTable(MonkeyType.A, CellType.L, MonkeyType.A, CellType.P, comp_AL_AP);
        addToTable(MonkeyType.M, CellType.L, MonkeyType.M, CellType.P, comp_ML_MP);
        addToTable(MonkeyType.A, CellType.L, MonkeyType.M, CellType.L, comp_AL_ML);
        addToTable(MonkeyType.A, CellType.P, MonkeyType.M, CellType.P, comp_AP_MP);
    }

    public void addCorrectedPValues(){
        BufferedReader reader = FileUtils.getBufferedReader(inputFromPValueCorrection);
        String line;
        Handle handle = Handle.getConnectedHandle("monkeys");
        try {
            while ((line = reader.readLine()) != null) {
                String split[] = line.split("\t");
                System.out.println(line);
                String sql = "update clusterIntersections set fdr="+split[10]+" where " +
                        "monkeyType_a = '"+split[0].substring(0, 1)+"' and monkeyType_b = '"+split[3].substring(0, 1)+"' and " +
                        "cellType_a = '"+split[0].substring(1, 2)+"' and cellType_b = '"+split[3].substring(1, 2)+"' and " +
                        "clusterId_a = "+split[1]+" and clusterId_b = "+split[4];
                handle.runSQLupdate(sql);
            }
            reader.close();
        } catch (IOException ex) {
            Logger.getLogger(ClusterIntersections.class.getName()).log(Level.SEVERE, null, ex);
        }
        handle.closeConnection();
    }


    private void addToTable(MonkeyType monkeyTypeA, CellType cellTypeA, MonkeyType monkeyTypeB, CellType cellTypeB, List<ClusterComparison> comparisons) {
        Handle handle = Handle.getConnectedHandle("monkeys");
        String sql;
        for(ClusterComparison cc : comparisons){
            sql = "insert into clusterIntersections values ("+id+", '"+monkeyTypeA+"', '"+cellTypeA+"', "+cc.getClusterIdA()+", "+cc.getSizeA()+", '"+monkeyTypeB+"', '"+cellTypeB+"', "+cc.getClusterIdB()+", "+cc.getSizeB()+", "+cc.getIntersectSize()+", "+cc.getRepresentation()+", "+cc.getMcc()+", "+cc.getpValue()+",1.0)";
            handle.runSQLupdate(sql);

            for(int probeId : cc.getIntersect()){
                sql = "insert into clusterIntersectionData values(0, "+id+", "+probeId+")";
                handle.runSQLupdate(sql);
            }
            id++;
        }

    }


    private int getProbeSetSize() {
        String sql = "select count(distinct probeId) from clustermembership where clusterId!=0";
        Handle handle = Handle.getConnectedHandle("monkeys");
        ResultSet rs = handle.runSQLquery(sql);
        int size = 0;
        try {
            if (rs.next()) {
                size = rs.getInt("count(distinct probeId)");
            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(ClusterIntersections.class.getName()).log(Level.SEVERE, null, ex);
        }
        handle.closeConnection();
        return size;
    }

    private void fillClusterMembership() {
        clusterMembership = new TreeMap<String, TreeMap<Integer, List<Integer>>>();
        Handle handle = Handle.getConnectedHandle("monkeys");
        String sql = "select distinct clusterId, probeId, monkeyType, cellType from clusterMembership where clusterId!=0 order by clusterId, probeId";
        ResultSet rs = handle.runSQLquery(sql);
        try {
            while (rs.next()) {
                String source = rs.getString("monkeyType") + rs.getString("cellType");
                int clusterId = rs.getInt("clusterId");
                int probeId = rs.getInt("probeId");
                if (!clusterMembership.containsKey(source)) {
                    clusterMembership.put(source, new TreeMap<Integer, List<Integer>>());
                }
                if (!clusterMembership.get(source).containsKey(clusterId)) {
                    clusterMembership.get(source).put(clusterId, new ArrayList<Integer>());
                }
                clusterMembership.get(source).get(clusterId).add(probeId);


            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(ClusterIntersections.class.getName()).log(Level.SEVERE, null, ex);
        }
        handle.closeConnection();
    }

    private List<ClusterComparison> makeClusterComparisons(String sourceA, String sourceB) {
        List<ClusterComparison> comparisons = new ArrayList<ClusterComparison>();
        TreeMap<Integer, List<Integer>> membershipA = clusterMembership.get(sourceA);
        TreeMap<Integer, List<Integer>> membershipB = clusterMembership.get(sourceB);

        for (int clusterIdA : membershipA.keySet()) {
            List<Integer> listA = membershipA.get(clusterIdA);
            for (int clusterIdB : membershipB.keySet()) {
                if (clusterIdA <= clusterIdB) {
                    List<Integer> listB = membershipB.get(clusterIdB);
                    ClusterComparison cc = new ClusterComparison(sourceA, sourceB, clusterIdA, clusterIdB, listA, listB);
                    comparisons.add(cc);

                }
            }
        }
        return comparisons;
    }

    private void output(String sourceA, String sourceB, List<ClusterComparison> comparisons) throws IOException {
        File outFile = new File(outputFolder, sourceA+"_"+sourceB+".txt");
        BufferedWriter writer = FileUtils.getBufferedWriter(outFile);
        
        for(ClusterComparison cc : comparisons){
            writer.append(cc.toString()+"\n");
            if(cc.getRepresentation()==1){
                pValuesWriter.append(cc.toString()+"\n");
            }
        }
        
        writer.close();
    }







    private class ClusterComparison {

        private String sourceA;
        private String sourceB;
        private int clusterIdA;
        private int clusterIdB;
        private int intersectSize;
        private int sizeA;
        private int sizeB;
        private double pValue;
        private double mcc;
        private int representation;
        private ArrayList<Integer> intersect;


        private ClusterComparison(String sourceA, String sourceB, int clusterIdA, int clusterIdB, List<Integer> listA, List<Integer> listB) {
            this.sourceA = sourceA;
            this.sourceB = sourceB;
            this.sizeA = listA.size();
            this.sizeB = listB.size();
            this.clusterIdA = clusterIdA;
            this.clusterIdB = clusterIdB;
            setIntersectValues(listA, listB);
        }

        public String getSourceA() {
            return sourceA;
        }

        public String getSourceB() {
            return sourceB;
        }

        public int getSizeA() {
            return sizeA;
        }

        public int getSizeB() {
            return sizeB;
        }

        public int getRepresentation() {
            return representation;
        }

        public int getClusterIdA() {
            return clusterIdA;
        }

        public void setClusterIdA(int clusterIdA) {
            this.clusterIdA = clusterIdA;
        }

        public int getClusterIdB() {
            return clusterIdB;
        }

        public void setClusterIdB(int clusterIdB) {
            this.clusterIdB = clusterIdB;
        }

        public int getIntersectSize() {
            return intersectSize;
        }

        public void setIntersectSize(int intersectSize) {
            this.intersectSize = intersectSize;
        }

        public double getMcc() {
            return mcc;
        }

        public void setMcc(double mcc) {
            this.mcc = mcc;
        }

        public double getpValue() {
            return pValue;
        }

        public void setpValue(double pValue) {
            this.pValue = pValue;
        }

        private void setIntersectValues(List<Integer> listA, List<Integer> listB) {
            intersect = new ArrayList<Integer>();
            intersect.addAll(listA);
            intersect.retainAll(listB);
            intersectSize = intersect.size();

            if (intersectSize > 0) {
                int tp = intersectSize;
                int tn = probeSetSize - (listA.size() + listB.size() - intersectSize);
                int fp = listA.size() - intersectSize;
                int fn = listB.size() - intersectSize;
                double propA = (listA.size() + 0.0) / probeSetSize;
                double propB = ((intersectSize + 0.0) / listB.size());
                if (propB > propA) {
                    representation = 1;
                } else if (propA > propB) {
                    representation = -1;
                } else {
                    representation = 0;
                }
                FishersExactTest fet = new FishersExactTest(probeSetSize, listA.size(), listB.size(), intersectSize);
                pValue= fet.getResult();
                mcc = Matthews.getMCC(tp, fp, tn, fn);
            } else {
                mcc = 0;
                pValue = 1;
                representation = -1;

            }
        }

        public ArrayList<Integer> getIntersect() {
            return intersect;
        }

        

        @Override
        public String toString(){
            return sourceA+"\t"+clusterIdA+"\t"+sizeA+"\t"+sourceB+"\t"+clusterIdB+"\t"+sizeB+"\t"+intersectSize+"\t"+representation+"\t"+mcc+"\t"+pValue;
        }
    }
}
